﻿using ProjScan.Modules;
using ProjScan.RecordManager.AssetData;
using ProjScan.ScanRule;
using ProjScan.Submodules.Effects_Play_Check;
using ProjScan.Tools;
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading;
using UnityEditor;
using UnityEngine;

namespace ProjScan.RecordManager
{
    internal class ParticleEffectRecordManager : RecordManagerBase<ParticleEffectAssetData>
    {
        private Dictionary<GameObject, ParticleSystemDrawer> particleSystemDrawersDict = new Dictionary<GameObject, ParticleSystemDrawer>();

        private int assetCounter;

        private Timer drawTimer;

        public bool isPreparingAssets = false;

        private float defaultRenderTime = 2f;

        private float remainingTimeSum;

        private GameObject currentGameObject = null;

        private ParticleEffectAssetData currentParticleEffectAssetData;

        private bool isEditorUpdatesAdded = false;

        private bool isDrawingNextAsset = false;

        public override string TableTag => "particleeffect";

        public override void PrepareAssets()
        {
            Singleton<PerformanceMeasurer>.Instance.StartStateExecutionMeasure("EffectPrepare");
            datas = new List<ParticleEffectAssetData>();
            int num = AssetPathManager.Instance.prefabPathList.Length;
            for (int i = 0; i < num; i++)
            {
                EditorUtility.DisplayProgressBar("Proj Scan [ParticleEffectProfiler]", "Preparing Effects (" + datas.Count + ")...", (float)i * 1f / (float)num);
                if (i % 50 == 0)
                {
                    ToolsHelper.GC();
                }

                string text = AssetPathManager.Instance.prefabPathList[i];
                ActiveAllRecord();
                if (!CheckAssetPathRules(text))
                {
                    continue;
                }

                GameObject gameObject = AssetDatabase.LoadAssetAtPath(text, typeof(GameObject)) as GameObject;
                if (!(gameObject != null))
                {
                    continue;
                }

                int iD = AssetPathManager.Instance.GetID(Path.GetDirectoryName(text));
                ParticleSystem[] componentsInChildren = gameObject.GetComponentsInChildren<ParticleSystem>(includeInactive: true);
                if (componentsInChildren != null && componentsInChildren.Length != 0)
                {
                    float num2 = defaultRenderTime;
                    ParticleSystem[] array = componentsInChildren;
                    foreach (ParticleSystem particleSystem in array)
                    {
                        ParticleSystem.MainModule main = particleSystem.main;
                        float b = (main.duration > 3f) ? main.duration : (main.duration * 2f);
                        num2 = Mathf.Min(Mathf.Max(num2, b), 10f);
                    }

                    remainingTimeSum += num2;
                    ParticleEffectAssetData item = new ParticleEffectAssetData(gameObject.name, iD, text, num2)
                    {
                        id = datas.Count
                    };
                    datas.Add(item);
                }
            }

            EditorUtility.ClearProgressBar();
            Singleton<PerformanceMeasurer>.Instance.StopStateExecutionMeasure(datas.Count);
            Singleton<PerformanceMeasurer>.Instance.StartStateExecutionMeasure("EffectPlay");
            StartDrawingAssets();
        }

        public override void Close()
        {
            if (datas != null)
            {
                datas.Clear();
            }
        }

        private void StartDrawingAssets()
        {
            isPreparingAssets = true;
            assetCounter = 0;
            RendererSetting.Initialize();
            EditorApplication.update = (EditorApplication.CallbackFunction)Delegate.Combine(EditorApplication.update, new EditorApplication.CallbackFunction(HandleEditorUpdates));
            ApiCompatibilityUtils.Instance.RegisterEditorExitPlayMode(ExitPlayModeCallback);
            ApiCompatibilityUtils.Instance.RegisterEditorPauseMode(HandleEditorPauseMode);
            isEditorUpdatesAdded = true;
            drawTimer = new Timer(EndDrawTimerCallback, null, -1, -1);
            DrawNextAsset(continueDrawing: false);
        }

        private void HandleEditorPauseMode(bool isPaused)
        {
            if (isEditorUpdatesAdded && isPaused)
            {
                EditorApplication.update = (EditorApplication.CallbackFunction)Delegate.Remove(EditorApplication.update, new EditorApplication.CallbackFunction(HandleEditorUpdates));
                isEditorUpdatesAdded = false;
            }
            else if (!isEditorUpdatesAdded && !isPaused)
            {
                EditorApplication.update = (EditorApplication.CallbackFunction)Delegate.Combine(EditorApplication.update, new EditorApplication.CallbackFunction(HandleEditorUpdates));
                isEditorUpdatesAdded = true;
            }
        }

        private void TerminateDrawingSession()
        {
            EditorUtility.ClearProgressBar();
            isPreparingAssets = false;
            EffectPerformanceMonitor.I.StopRunning();
            if (isEditorUpdatesAdded)
            {
                EditorApplication.update = (EditorApplication.CallbackFunction)Delegate.Remove(EditorApplication.update, new EditorApplication.CallbackFunction(HandleEditorUpdates));
                isEditorUpdatesAdded = false;
            }

            Singleton<PerformanceMeasurer>.Instance.StopStateExecutionMeasure(datas.Count);
            Singleton<EffectsPlayCheckModule>.Instance.Close();
        }

        private void TerminateImmediate()
        {
            Debug.Log("Terminated by force");
            TerminateDrawingSession();
        }

        private void DrawNextAsset(bool continueDrawing)
        {
            if (continueDrawing)
            {
                EndDrawingCurrentAsset();
            }

            if (assetCounter == datas.Count)
            {
                TerminateDrawingSession();
                return;
            }

            EditorUtility.DisplayProgressBar("Proj Scan [ParticleEffectProfiler]", "Recording Effects (" + assetCounter + "/" + datas.Count + ")...", (float)assetCounter * 1f / (float)datas.Count);
            Debug.Log("Analyzing Effect: " + (assetCounter + 1) + "/" + datas.Count);
            int index = assetCounter++;
            currentParticleEffectAssetData = datas[index];
            if (assetCounter % 50 == 0)
            {
                ToolsHelper.GC();
            }

            Debug.Log("Path: @" + currentParticleEffectAssetData.fileLocation);
            GameObject gameObject = AssetDatabase.LoadAssetAtPath(currentParticleEffectAssetData.fileLocation, typeof(GameObject)) as GameObject;
            if (gameObject == null)
            {
                DrawNextAsset(continueDrawing: false);
                return;
            }

            gameObject.SetActive(value: false);
            currentGameObject = UnityEngine.Object.Instantiate(gameObject);
            gameObject.SetActive(value: true);
            List<Type> list = new List<Type>();
            list.Add(typeof(Transform));
            list.Add(typeof(ParticleSystem));
            list.Add(typeof(ParticleSystemRenderer));
            Component[] componentsInChildren = currentGameObject.GetComponentsInChildren<Component>();
            int num = 5;
            while (num-- > 0)
            {
                Component[] array = componentsInChildren;
                foreach (Component component in array)
                {
                    if (component != null)
                    {
                        Type type = component.GetType();
                        if (type != null && type.IsSubclassOf(typeof(MonoBehaviour)))
                        {
                            UnityEngine.Object.DestroyImmediate(component);
                        }

                        if ((!(type == null) && type.IsAssignableFrom(typeof(MeshFilter))) || type.IsAssignableFrom(typeof(MeshRenderer)))
                        {
                            UnityEngine.Object.DestroyImmediate(component);
                        }
                    }
                }
            }

            currentGameObject.GetComponentsInChildren<ParticleSystem>(includeInactive: true);
            currentGameObject.SetActive(value: true);
            ParticleSystemDrawer particleSystemDrawer = null;
            try
            {
                particleSystemDrawer = new ParticleSystemDrawer(currentGameObject);
                particleSystemDrawersDict.Add(currentGameObject, particleSystemDrawer);
            }
            catch (Exception ex)
            {
                ScanLog.Instance.LogInfo(ScanLog.LogLevel.EXCEPTION, Module.Effects_Play_Check, TableTag, ((ex.GetType() == null) ? null : ex.GetType().ToString()) + "\n" + ex.Message + "\n" + ex.StackTrace);
                Debug.LogError("特效异常：" + currentGameObject.name + ", 请检测该特效是否能正常显示。");
                UnityEngine.Object.DestroyImmediate(currentGameObject);
                DrawNextAsset(continueDrawing: false);
                return;
            }

            RendererSetting.SetParticleSystemDrawer(particleSystemDrawer);
            EffectPerformanceMonitor.I.Initialize();
            EffectPerformanceMonitor.I.StartMonitoring(currentGameObject, particleSystemDrawer);
            Debug.Log("RenderTime: " + currentParticleEffectAssetData.renderTime);
            Debug.Log("预计剩余时间：" + remainingTimeSum + "s");
            drawTimer.Change((int)(currentParticleEffectAssetData.renderTime * 1000f), -1);
            remainingTimeSum -= currentParticleEffectAssetData.renderTime;
        }

        private void EndDrawTimerCallback(object object_0)
        {
            isDrawingNextAsset = true;
        }

        private void EndDrawingCurrentAsset()
        {
            EffectPerformanceMonitor.I.StopRunning();
            EffectPerformanceMonitor.I.AssignData(currentParticleEffectAssetData);
            RendererSetting.ClearEditorUpdates();
            particleSystemDrawersDict[currentGameObject].Dispose();
            UnityEngine.Object.DestroyImmediate(currentGameObject);
            CheckAssetPathRules(currentParticleEffectAssetData.fileLocation);
            foreach (RecordRule recordRule in recordRules)
            {
                if (dicEnableRules[recordRule])
                {
                    recordRule.Check(currentParticleEffectAssetData);
                }
            }

            currentParticleEffectAssetData.Reset();
        }

        private void HandleEditorUpdates()
        {
            if (isDrawingNextAsset)
            {
                isDrawingNextAsset = false;
                DrawNextAsset(continueDrawing: true);
            }
        }

        private void ExitPlayModeCallback()
        {
            if (isPreparingAssets)
            {
                TerminateImmediate();
            }
        }
    }
}